﻿// UseMutexLock.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include<mutex>
#include<stack>

// 共享变量
int shared_data = 100;

// mutex
std::mutex mtx1;


void use_lock() {
	while (true)
	{
		mtx1.lock();
		shared_data++;
		std::cout << "current thread id is" << std::this_thread::get_id() << std::endl;
		std::cout << "current shared_data id is" << shared_data << std::endl;
		mtx1.unlock();
		// 防止死循环
		std::this_thread::sleep_for(std::chrono::microseconds(1));
	}
}

void test_lock() {
	// 方式一 函数 创建Thread
	std::thread t1(use_lock);
	// 方式二 lambda表达式 创建Thread
	std::thread t2([]() {
		mtx1.lock();
		shared_data--;
		std::cout << "current thread id is" << std::this_thread::get_id() << std::endl;
		std::cout << "current shared_data id is" << shared_data << std::endl;
		mtx1.unlock();
		// 防止死循环
		std::this_thread::sleep_for(std::chrono::microseconds(10));
		});

	t1.join();
	t2.join();
}

// 采用线程守卫
void test_lock_guard() {
	// 方式一 函数 创建Thread
	std::thread t1(use_lock);
	// 方式二 lambda表达式 创建Thread
	std::thread t2([]() {
		// 放在局部空间，防止 lock_guard 没必要的占用资源（sleep_for 休眠了10毫秒），
		{
			std::lock_guard<std::mutex> lk_guard(mtx1);
			shared_data--;
			std::cout << "current thread id is" << std::this_thread::get_id() << std::endl;
			std::cout << "current shared_data id is" << shared_data << std::endl;
		}
		// 防止死循环
		std::this_thread::sleep_for(std::chrono::microseconds(10));
		});

	t1.join();
	t2.join();
}

template<typename T>
class threadsafe_stack1
{
private:
	// 定义线程安全栈
	std::stack<T> data;
	// 定义mutex
	mutable std::mutex m;

public:
	threadsafe_stack1() {};
	// 定义拷贝构造
	threadsafe_stack1(const threadsafe_stack1& other) {
		// 加锁，防止其他数据拷贝时修改
		std::lock_guard<std::mutex> lock_guard(other.m);
		data = other.data;
	};

	// 拷贝赋值去掉
	threadsafe_stack1& operator=(const threadsafe_stack1& other) = delete;


	~threadsafe_stack1() {};


	void push(T new_value) {
		std::lock_guard<std::mutex> lock_guard(m);
		// move 减少一次拷贝构造
		data.push(std::move(new_value));
	}

	// 如下pop代码存在问题
	T pop() {
		std::lock_guard<std::mutex> lock_guard(m);
		auto element = data.top();
		data.pop();
		return element;
	}

	// 危险
	bool is_empty()const {
		std::lock_guard<std::mutex> lock_guard(m);
		return data.empty();
	}


};


// 定义一个空栈异常
struct empty_stack :std::exception {
	const char* what()const throw();
};


template<typename T>
class threadsafe_stack
{
private:
	// 定义线程安全栈
	std::stack<T> data;
	// 定义mutex
	mutable std::mutex m;

public:
	threadsafe_stack() {};
	// 定义拷贝构造
	threadsafe_stack(const threadsafe_stack& other) {
		// 加锁，防止其他数据拷贝时修改
		std::lock_guard<std::mutex> lock_guard(other.m);
		data = other.data;
	};

	// 拷贝赋值去掉
	threadsafe_stack& operator=(const threadsafe_stack& other) = delete;


	~threadsafe_stack1() {};


	void push(T new_value) {
		std::lock_guard<std::mutex> lock_guard(m);
		// move 减少一次拷贝构造
		data.push(std::move(new_value));
	}

	
	T pop() {
		std::lock_guard<std::mutex> lock_guard(m);
		// 判断栈是否为空
		if (data.empty())
		{
			throw empty_stack();
		}
		// 后续element 元素过大也有可能导致其他异常 
		auto element = data.top();
		data.pop();
		return element;
	}

	std::shared_ptr<T> pop_byptr() {
		std::lock_guard<std::mutex> lock_guard(m);
		// 判断栈是否为空
		if (data.empty())
		{
			throw empty_stack();
		}
		
		// 后续element 元素过大也有可能导致其他异常 
		std::shared_ptr<T> const res(std::make_shared<T>(data.top()));
		data.pop();
		return res;
	}

	// 传递引用
	T pop_byref(T& value) {
		std::lock_guard<std::mutex> lock_guard(m);
		// 判断栈是否为空
		if (data.empty())
		{
			throw empty_stack();
		}
		// 后续element 元素过大也有可能导致其他异常 
		value = data.top();
		data.pop();
	}

	// 危险
	bool is_empty()const {
		std::lock_guard<std::mutex> lock_guard(m);
		return data.empty();
	}


};

void test_threadsafe_stack1() {
	threadsafe_stack1<int> safe_stack;
	safe_stack.push(1);

	std::thread t1([&safe_stack]() {
		if (!safe_stack.is_empty()) {
			// 线程1和线程2 判断两者都不为空，导致pop()异常
			std::this_thread::sleep_for(std::chrono::seconds(1));
			safe_stack.pop();
		}
		});
	std::thread t2([&safe_stack]() {
		if (!safe_stack.is_empty()) {
			std::this_thread::sleep_for(std::chrono::seconds(1));
			safe_stack.pop();
		}
		});


	t1.join();
	t2.join();
}

int main()
{
	//test_lock();
	test_lock_guard();
	std::cout << "Hello Multi Thread and Mutex!\n";
}

